package br.com.amethyst.workflow.source;

import java.io.File;
import java.net.URI;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.stream.StreamSource;
import org.xml.sax.SAXException;
import br.com.amethyst.workflow.exception.WorkflowSourceLoadException;
import br.com.amethyst.workflow.exception.WorkflowSourceValidationException;

/**
 * Abstract Workfow Source with some basic methods initialized
 * 
 * @author Artur Figueira <arturfigueira@gmail.com>
 * 
 */
abstract class AbstractWorkflowSource implements IWorkflowSource
{
	
	protected String sourcePath;
	protected String sourceFileSystemId;
	protected StreamSource source;
	protected boolean noNameSpaceLocation = false;

	public static final String W3C_XMLSCHEMA 		= "http://www.w3.org/2001/XMLSchema";
	public static final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
	public static final String JAXP_SCHEMA_SOURCE 	= "http://java.sun.com/xml/jaxp/properties/schemaSource";

	/**
	 * Return's the path of a XSD Schema
	 * Must be implemented by a sub-class
	 * @return XSD Schema Path
	 */
	protected abstract String getSchemaPath();

	@Override
	public void noNameSpaceLocation(){
		this.noNameSpaceLocation = true;
	}
	
	@Override
	public StreamSource getSource(){
		return this.source;
	}

	@Override
	public boolean doValidate() throws WorkflowSourceValidationException
	{
		try
		{
			//Check if sourcePath is null or empty.
			if(this.sourcePath == null || "".equals(this.sourcePath))
				throw new WorkflowSourceValidationException("SourcePath cannot be null or empty");
			
			//Check if the Sub-Class SchemaPath is null or empty
			if(getSchemaPath() == null || "".equals(getSchemaPath()))
				noNameSpaceLocation = true;
	        
			//Create a DOMDocument Parser setting the W3C schema as Schema Language
			//In this case we are using SpaceLocation, so to be able to validate we must set the schema source
	        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
	        factory.setValidating(true);											//Validate the file during the parser
	        factory.setNamespaceAware(true); 										//Set it to check namesSpaces
	        factory.setAttribute(JAXP_SCHEMA_LANGUAGE, W3C_XMLSCHEMA);				//Schema Language URL
	        
	        //set as schema source property the XSD's Schema URL if it's necessary to validate a schema
	        if(!noNameSpaceLocation)
	        	factory.setAttribute(JAXP_SCHEMA_SOURCE, new File(getSchemaPath()));	
	        
	        //Finally create the document Parser with
	        DocumentBuilder docParser	 = factory.newDocumentBuilder();
	         
	        //Check the document
	        try 
	        {
	        	docParser.parse(this.sourcePath);
	            return true;
	        }
	        catch (SAXException ex)
	        {
	        	return  false;
	        }
		}
		catch (Exception e) {
			throw new WorkflowSourceValidationException(e.getMessage());
		}
	}

	@Override
	public void load(String sourcePath) throws WorkflowSourceLoadException
	{
		try{
			if(sourcePath == null || "".equals(sourcePath))
				throw new WorkflowSourceLoadException("WorkflowSource can't be lodaded because the path is null or empty");
		
			this.sourcePath = sourcePath;
			
			//Generate an Unique System location based on the element type
			URI systemURI 				= new File(sourcePath).toURI();	
			
			//Generate an Unique Location of the file depending on the OS
			this.sourceFileSystemId 	= systemURI.toURL().toExternalForm();
			
			//Create a new instance of StreamSource
			this.source					= new StreamSource(sourceFileSystemId);
		}
		catch (Exception e) {
			throw new WorkflowSourceLoadException(e.getMessage());
		}
	}

}
